--Ejercicio 1

ultimo :: [Integer] -> Integer
ultimo [y] = y 
ultimo (x:xs) = ultimo xs

principio :: [Integer] -> [Integer]
principio [x,y] = [x]
principio (x:xs) = x : principio (xs) 

header :: [a] -> a
header (x:_) = x

todosIguales :: [Integer] -> Bool
todosIguales [x]= True
todosIguales (x:xs) = if x == header xs then todosIguales xs else False

                 
todosDiferentes :: [Integer] -> Bool    -- tiene un error no se donde
todosDiferentes [] = True
todosDiferentes (x:xs)
    |elem x xs = False
    |otherwise = todosDiferentes xs

mismosElem ::  [Integer]->[Integer] -> Bool 
mismosElem [] (x:xs) = True
mismosElem (x:xs) (y:ys) | elem  x (y:ys) = mismosElem xs (y:ys)
                      |otherwise = False
--Ejercicio 2

sacarTodos :: [Char] -> [Char] -> [Char]
sacarTodos x (y:ys)
   | length x > length (y:ys) = (y:ys)
   | length x == length (y:ys) = (sacarDelPrincipio x (y:ys))
   | (esPrefijo x (y:ys)) = (sacarTodos x (sacarPrefijo x (y:ys)))
   | (not (esPrefijo x (y:ys)))= (y:(sacarTodos x ys))


sacarBlancosRepetidos :: [Char] -> [Char]
sacarBlancosRepetidos []       = []
sacarBlancosRepetidos (x:xs)
   | x==' '          = if (head xs)==' ' then (sacarBlancosRepetidos xs) else (x:(sacarBlancosRepetidos xs))
   | otherwise         = (x:(sacarBlancosRepetidos xs))


---------------



contarPalabras :: [Char] -> Integer
contarPalabras []    = 0
contarPalabras (x:[])    = 1
contarPalabras (x:xs)
   | x==' '   = 1 + (contarPalabras xs)
   | otherwise = (contarPalabras xs)

---------------------------
aplanar :: [[Char]] -> [Char]
aplanar ((x:xs):[])    = (x:xs)
aplanar ((x:xs):(y:ys)) = (x:xs)++(aplanar (y:ys))


aplanarConBlancos :: [[Char]] -> [Char]
aplanarConBlancos ((x:xs):[])       = (x:xs)
aplanarConBlancos ((x:xs):(y:ys))   = (x:xs)++[' ']++(aplanarConBlancos (y:ys))


aplanarConNBlancos :: [[Char]] -> Integer -> [Char]
aplanarConNBlancos ((x:xs):[]) n   = (x:xs)
aplanarConNBlancos ((x:xs):(y:ys)) n   = (x:xs) ++ (nBlancos n) ++(aplanarConNBlancos (y:ys) n)


nat2bin :: Integer -> [Integer]
nat2bin 0 = [0]
nat2bin 1 = [1]
nat2bin n = (nat2bin (div n 2)) ++ [mod n 2]


bin2nat :: [Integer] -> Integer
bin2nat [] = 0
bin2nat (x:xs) = x * (2^(length xs)) + (bin2nat xs)


nat2hex :: Integer -> [Char]
nat2hex 1    = ['1']
nat2hex 2    = ['2']
nat2hex 3    = ['3']
nat2hex 4    = ['4']
nat2hex 5    = ['5']
nat2hex 6    = ['6']
nat2hex 7    = ['7']
nat2hex 8    = ['8']
nat2hex 9    = ['9']
nat2hex 10    = ['A']
nat2hex 11    = ['B']
nat2hex 12    = ['C']
nat2hex 13    = ['D']
nat2hex 14    = ['E']
nat2hex 15    = ['F']
nat2hex n = (nat2hex (div n 16)) ++ (nat2hex (mod n 16))
-- ejercicio 3 practica 7
ej3::Int->Int
ej3 x = mainRepeticiones (listaRepeticiones x 20)

mainRepeticiones::[Int] -> Int
mainRepeticiones []     = -1
mainRepeticiones (x:xs) | x `elem` xs = x
                    |otherwise = mainRepeticiones xs

listaRepeticiones::Int->Int->[Int]
listaRepeticiones x 0 = []
listaRepeticiones x y = x:(listaRepeticiones (reducir x) (y-1))

reducir::Int->Int
reducir 0 = 0
reducir x = digitosMult x

digitosMult::Int->Int
digitosMult 0 = 2
digitosMult x = (x `mod` 10) * (digitosMult (x `div` 10))
--ejercicio 4 practica 7

lMl :: [Int] -> [Int]
lMl [] = []
lMl x = maximasuma (listas x)

listas :: [Int] -> [[Int]]
listas [] = [[]]
listas (x:xs) = (sublista (x:xs)) ++ (sublista xs)

sublista ::[Int] -> [[Int]]
sublista [] = []
sublista x = [x] ++ [sacaU x] ++ [sacaP x] ++ sublista (sacaP(sacaU x))

sacaU :: [a] -> [a]
sacaU [a] = []
sacaU (x:xs) = (x:(sacaU xs))

sacaP :: [a] -> [a]
sacaP [] = []
sacaP [a] = []
sacaP (x:xs) = xs

maximasuma :: [[Int]] -> [Int]
maximasuma [] = []
maximasuma (x:xs) = sumas x xs

sumas :: [Int] -> [[Int]] ->[Int]
sumas l [] = l
sumas l  (x:xs)
   |sum l > sum x = sumas l xs
   |otherwise = sumas x xs  


--ejercicio 5 practica 7

ordAs ::  [Integer] -> [Integer]
ordAs [] = []
ordAs (ls) = (ordAsAux (ls) [])

orDes :: [Integer] ->  [Integer]
orDes [] =[]
orDes ls = reverse (ordAsAux ls [])

inserte::Ord a => a -> [a] ->[a]
inserte e [] = [e]
inserte e (x:xs)
   | e <= x = e:(x:xs) 
   | otherwise = (x:(inserte e xs))             


ordAsAux :: Ord a => [a]-> [a]-> [a]
ordAsAux [] xs = xs
ordAsAux (x:xs) ls = (ordAsAux xs (inserte x ls)) 

listadlis :: Ord a => [a] -> [[a]]
listadlis [] = []
listadlis ls = listass ((ordAsAux ls []))

listass :: Eq a => [a] ->  [[a]]
listass [] = []
listass [x] = [[x]]
listass (e:(x:xs)) 
    | e == x = (++) [e: (iguales x xs)]  (listass (saCar e (x:xs)))  
    |otherwise = (++)[[e]] (listass (x:xs))

iguales :: Eq a => a -> [a] -> [a]
iguales n [] = [n]
iguales n (m:ms) 
   | n == m = m:(iguales n ms)
   | otherwise = (iguales n ms)  
   
--Ejercicio 6

reverso :: Eq a => [a]-> [a]
reverso [] = []
reverso (x:xs) = (reverso xs) ++ [x]

capicua :: Ord a =>[a] -> Bool
capicua [] = True
capicua [a] = True
capicua (xs) 
     | head xs == ult xs = capicua (sacarPyU xs)
     |otherwise = False
     
sacarPyU ::Eq a =>[a] -> [a]
sacarPyU [] = []
sacarPyU (x:xs) = sacaU xs


sumacum :: [Int] -> [Int]
sumacum [] = []
sumacum (x:xs) =sumacum (sacaU (x:xs)) ++ [sum (x:xs)]

descomponerEnPrimos :: [Int] -> [[Int]]
descomponerEnPrimos [] = []
descomponerEnPrimos (x:xs) = factPrimos x 2:descomponerEnPrimos xs

factPrimos :: Int -> Int -> [Int]
factPrimos x y | esPrimo x 2 = [x]
factPrimos x y 
  | x`mod`y==0 = y:(factPrimos (x`div`y) y)
  | otherwise = factPrimos x (y+1)

esPrimo :: Int -> Int -> Bool
esPrimo x y
  | x==y = True
  | x`mod`y/=0 = esPrimo x (y+1)
  |otherwise = False

---- FUNCIONES AUXILIARES ----
cola :: [a] -> [a]
cola [] = []
cola (_:xs) = xs

saCar :: Eq a => a -> [a] -> [a]
saCar a [] = []
saCar a (x:xs)
        | a == x = saCar a xs
        |otherwise = x: (saCar a xs)



sacarDelPrincipio :: [Char] -> [Char] -> [Char]
sacarDelPrincipio x y
   | (esPrefijo x y) = (sacarPrefijo x y)
   | (not (esPrefijo x y)) = y

esPrefijo :: [Char] -> [Char] -> Bool
esPrefijo [] y = True
esPrefijo (x:xs) [] = False
esPrefijo (x:xs) (y:ys)
   | x==y = (esPrefijo xs ys)
   | otherwise = False

sacarPrefijo :: [Char] -> [Char] -> [Char]
sacarPrefijo [] y = y
sacarPrefijo (x:xs) (y:ys) = sacarPrefijo xs ys

nBlancos :: Integer -> [Char]
nBlancos 0 = []
nBlancos n = [' ']++ (nBlancos (n-1))

ult :: [a] -> a
ult (x:[]) = x
ult (x:xs) = ult xs